package io.xxx.omni.osc.sdk

import com.dangdang.openplatform.openapi.sdk.SdkClient
import com.kuaishou.merchant.open.api.client.AccessTokenKsMerchantClient
import com.kuaishou.merchant.open.api.client.oauth.OauthAccessTokenKsClient
import com.suning.api.DefaultSuningClient
import io.xxx.omni.osc.client.PlatformClient
import io.xxx.omni.osc.client.StoreClient
import io.xxx.omni.osc.domain.Platform
import io.xxx.omni.osc.domain.PlatformIdentity
import io.xxx.omni.osc.domain.Store
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.InitializingBean
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationContextAware
import org.springframework.context.support.GenericApplicationContext
import org.springframework.scheduling.annotation.Scheduled
import org.springframework.stereotype.Component

@Component
class ClientHousekeeper : InitializingBean, ApplicationContextAware {

    private val log: Logger = LoggerFactory.getLogger(javaClass)

    private lateinit var applicationContext: GenericApplicationContext

    @Autowired
    private lateinit var platformClient: PlatformClient

    @Autowired
    private lateinit var storeClient: StoreClient

    private val storesCache = mutableMapOf<String, Store>()

    @Scheduled(cron = "0/5 * * * * ?")
    fun flushClient() {
        val platforms = platformClient.getAll()
        for (platform in platforms) {
            if (platform.enabled) {
                flushClient(platform)
            }
        }
    }

    private fun flushClient(platform: Platform) {
        val stores = storeClient.getAll(platform.id)
        for (store in stores) {
            val authorization = store.authorization
            val oldStore = storesCache[store.id]
            if (oldStore != null && authorization <= oldStore.authorization)
                return

            val clients = getClients(platform, store)
            if (clients.isNotEmpty()) {
                val registered = registerSingleton(clients)
                if (registered) {
                    this.storesCache[store.id] = store
                    log.info("${store.pid}Client${store.id} 已经更新")
                }
            }
        }
    }

    private fun getClients(platform: Platform, store: Store): Map<String, Any> {
        val beanNamePrefix = "${platform.id}Client"
        val authorization = store.authorization

        return when (platform.id) {
            object : PlatformIdentity.SuNing {}.platformId() -> {
                val serverUrl = "https://open.suning.com/api/http/sopRequest"
                val beanName = "${beanNamePrefix}${store.id}"
                val appKey = authorization["appKey"]
                val appSecret = authorization["appSecret"]
                val client = DefaultSuningClient(serverUrl, appKey, appSecret, "json")
                mapOf(beanName to client)
            }
            object : PlatformIdentity.DangDang {}.platformId() -> {
                fun getClient(version: String): SdkClient {
                    val appKey = authorization["appKey"]
                    val appSecret = authorization["appSecret"]
                    val session = authorization["session"]
                    return SdkClient(appKey, appSecret, session, version)
                }

                val beanName1 = "${beanNamePrefix}V1${store.id}"
                val beanName2 = "${beanNamePrefix}V2${store.id}"
                val beanName3 = "${beanNamePrefix}V3${store.id}"
                mapOf(
                    beanName1 to getClient("1.0"),
                    beanName2 to getClient("2.0"),
                    beanName3 to getClient("3.0"),
                )
            }
            object : PlatformIdentity.KuaiShou {}.platformId() -> {
                val beanName = "${beanNamePrefix}${store.id}"
                val appKey = authorization["appKey"]
                val signSecret = authorization["signSecret"]
                val client = AccessTokenKsMerchantClient(null, appKey, signSecret)

                val oauthBeanName = "${platform.id}OauthClient${store.id}"
                val appSecret = authorization["appSecret"]
                val oauthClient = OauthAccessTokenKsClient(appKey, appSecret)
                mapOf(
                    beanName to client,
                    oauthBeanName to oauthClient
                )
            }
            else -> emptyMap()
        }
    }

    override fun setApplicationContext(applicationContext: ApplicationContext) {
        this.applicationContext = applicationContext as GenericApplicationContext
    }

    override fun afterPropertiesSet() {
        flushClient()
    }

    @Synchronized
    private fun registerSingleton(clients: Map<String, Any>): Boolean {
        var flag = false
        for ((beanName, client) in clients) {
            if (!applicationContext.isBeanNameInUse(beanName)) {
                applicationContext.beanFactory.registerSingleton(beanName, client)
                flag = true
            }
        }
        return flag
    }
}

